﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.IO;

namespace MathService.DSP.Signals
{
    public partial class DigitalSignal
    {
        public void SaveToStream(Stream DataStream)
        {
            Contract.Requires(DataStream != null);
            var lv_Writer = new StreamWriter(DataStream) { AutoFlush = true };

            var lv_WriteBuffer = @"t	|	" + Name;
            lv_Writer.WriteLine(lv_WriteBuffer);

            lv_WriteBuffer = new string('-', lv_WriteBuffer.Length);
            lv_Writer.WriteLine(lv_WriteBuffer);

            var dt = dx;
            var i_Length = SamplesCount;
            for(var i = 0; i < i_Length; i++)
            {
                lv_WriteBuffer = string.Format(@"{0}	|	{1}", i * dt, f_Samples[i]);
                lv_Writer.WriteLine(lv_WriteBuffer);
            }
        }

        public static void SaveToStream(Stream DataStream, IEnumerable<DigitalSignal> Signals)
        {
            SaveToStream(DataStream, new List<DigitalSignal>(Signals).ToArray());
        }

        public static void SaveToStream(Stream DataStream, params DigitalSignal[] Signals)
        {
            var lv_SignalsCount = Signals.Length;
            var dt = Signals[0].dx;
            var lv_SamplesCount = Signals[0].SamplesCount;

            var lv_Samples = new double[lv_SignalsCount][];

            for(var i = 0; i < lv_SignalsCount; i++)
            {
                if(Signals[i].dx != dt || Signals[i].SamplesCount != lv_SamplesCount)
                    throw new ArgumentException("Немогу записать сигналы с разным периодом дискретизации, либо с разной длительностью");
                lv_Samples[i] = Signals[i];
            }

            var lv_Writer = new StreamWriter(DataStream) { AutoFlush = true };

            var lv_WriteBuffer = @"x	";

            for(int i = 0, i_Length = lv_SignalsCount - 1; i < i_Length; i++)
                lv_WriteBuffer += string.Format("|	{0}\t", Signals[i].Name);
            lv_WriteBuffer += string.Format(@"|	{0}", Signals[lv_SignalsCount - 1].Name);
            lv_Writer.WriteLine(lv_WriteBuffer);

            lv_WriteBuffer = new string('-', lv_WriteBuffer.Length);
            lv_Writer.WriteLine(lv_WriteBuffer);

            for(var n = 0; n < lv_SamplesCount; n++)
            {
                lv_WriteBuffer = string.Format("{0}\t", n * dt);
                for(int i = 0, i_Length = lv_SignalsCount - 1; i < i_Length; i++)
                    lv_WriteBuffer += string.Format(@"|	{0}	", lv_Samples[i][n]);
                lv_WriteBuffer += string.Format(@"|	{0}", lv_Samples[lv_SignalsCount - 1][n]);
                lv_Writer.WriteLine(lv_WriteBuffer);
            }
        }

        private static string[] ParceBuffer(string Buffer)
        {
            var lv_Result = new List<string>(Buffer.Split('|', '\t'));
            lv_Result.RemoveAll("".Equals);

            return lv_Result.ToArray();
        }

        private static double[] GetSamples(string[] Buffer)
        {
            return Array.ConvertAll<string, double>(Buffer, double.Parse);
        }

        public static DigitalSignal[] ReadFromStream(Stream DataStream)
        {
            var lv_Reader = new StreamReader(DataStream);
            var lv_ReadBuffer = lv_Reader.ReadLine();
            var lv_ValueStrings = ParceBuffer(lv_ReadBuffer);
            var lv_SignalsCount = lv_ValueStrings.Length - 1;
            var lv_Names = new string[lv_SignalsCount];
            Array.Copy(lv_ValueStrings, 1, lv_Names, 0, lv_SignalsCount);

            var lv_Signals = new DigitalSignal[lv_SignalsCount];

            lv_Reader.ReadLine();

            var lv_Samples = new List<double>[lv_SignalsCount];
            for(var i = 0; i < lv_SignalsCount; i++)
                lv_Samples[i] = new List<double>(10000);

            lv_ReadBuffer = lv_Reader.ReadLine();
            lv_ValueStrings = ParceBuffer(lv_ReadBuffer);
            var lv_Values = GetSamples(lv_ValueStrings);
            for(var i = 0; i < lv_SignalsCount; i++)
                lv_Samples[i].Add(lv_Values[i + 1]);
            var x0 = lv_Values[0];

            lv_ReadBuffer = lv_Reader.ReadLine();
            lv_ValueStrings = ParceBuffer(lv_ReadBuffer);
            lv_Values = GetSamples(lv_ValueStrings);
            for(var i = 0; i < lv_SignalsCount; i++)
                lv_Samples[i].Add(lv_Values[i + 1]);
            var dx = lv_Values[0] - x0;

            while(lv_Reader.Peek() != -1)
            {
                lv_ReadBuffer = lv_Reader.ReadLine();
                lv_ValueStrings = ParceBuffer(lv_ReadBuffer);
                lv_Values = GetSamples(lv_ValueStrings);
                for(var i = 0; i < lv_SignalsCount; i++)
                    lv_Samples[i].Add(lv_Values[i + 1]);
            }

            for(var i = 0; i < lv_SignalsCount; i++)
                lv_Signals[i] = new DigitalSignal(dx, lv_Samples[i].ToArray()) { Name = lv_Names[i], x0 = x0 };

            return lv_Signals;
        }
    }
}